package com.atguigu.gmall.activity.listener;

import com.atguigu.gmall.activity.config.CacheHelper;
import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.utils.DateUtil;
import com.atguigu.gmall.common.constans.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.model.activity.OrderRecode;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;

/**
 * @author 李旭
 * @date 2022/2/9
 * @Description:
 *
 *   秒杀的商品监听器
 */
@Component
public class SeckillGoodsListener {


    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    //接收消息
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_1,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = {MqConst.ROUTING_TASK_1}
    ))
    public void receiverResult(Message message, Channel channel)  {
        try {
              //0:查询DB的数据
            /**
             * # 数据是当天的  商品的数据必须有货、必须是审核通过的
             * select * from seckill_goods
             * where `status` = 1 and stock_count > 0 and
             * DATE_FORMAT(start_time,'%Y-%m-%d') = '2022-02-09'
             *
             */
            QueryWrapper<SeckillGoods> queryWrapper = new QueryWrapper<SeckillGoods>();

            //必须是审核通过的
            queryWrapper.eq("status","1");
            //商品的数据必须有货
            queryWrapper.gt("stock_count",0);
            //数据是当天的
            queryWrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')", DateUtil.formatDate(new Date()));
            //执行查询
            List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(queryWrapper);
            //Redis: hash散列类型
            if(!CollectionUtils.isEmpty(seckillGoodsList)){
                for (SeckillGoods seckillGoods : seckillGoodsList) {
//            1、校验是否已经同步完成
                    if(!redisTemplate.opsForHash().hasKey(RedisConst.SECKILL_GOODS,
                            seckillGoods.getSkuId().toString())){
                        //            2、如果未完成、将DB中数据同步缓存中
                        //保存秒杀商品到缓存中
                        redisTemplate.opsForHash().put(RedisConst.SECKILL_GOODS,
                                seckillGoods.getSkuId().toString(),seckillGoods);

                        //提前将要秒杀的相应数量的商品本身直接保存到缓存的List类型中  防止商品超卖
                        redisTemplate.opsForList().leftPushAll(
                                RedisConst.SECKILL_STOCK_PREFIX + seckillGoods.getSkuId(),
                                 buildSeckillGoodsData(seckillGoods));// 30 push 10次
                        //状态位 群发
                        redisTemplate.convertAndSend("seckillpush",
                                seckillGoods.getSkuId() +":1");
                    }else{
                        //            3、如果已完成、不同步了
                        System.out.println("已完成、不同步了");
                    }

                }

            }
            //应答
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //准备商品本身  指定的商品本身
    private String[] buildSeckillGoodsData(SeckillGoods seckillGoods) {
        String[] skuIds = new String[seckillGoods.getStockCount()];
        for (Integer i = 0; i < seckillGoods.getStockCount(); i++) {
            skuIds[i] = seckillGoods.getSkuId().toString();
        }
        return skuIds;

    }

    //开始抢购的消息  接收
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_SECKILL_USER,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER),
            key = {MqConst.ROUTING_SECKILL_USER}
    ))
    public void receiverMessage(UserRecode userRecode,Message message, Channel channel)  {
        try{
//            1、校验状态位
            Object state = CacheHelper.get(userRecode.getSkuId().toString());
            if(!"1".equals(state)){
                //无货
                channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
                return;//代码不要往下运行了
            }
//            2、校验用户是否已买  setnx 如果买过 返回值 0  false  如果没有买过 返回值1 true
            Boolean isSale = redisTemplate.opsForValue().setIfAbsent(RedisConst.SECKILL_USER +
                    userRecode.getUserId() + ":" + userRecode.getSkuId(), "");
            if(isSale){
                //当前用户未买过
                // 3、校验是否还有货
                Object seckillGoods = redisTemplate.opsForList().rightPop(
                        RedisConst.SECKILL_STOCK_PREFIX + userRecode.getSkuId());
                if(null == seckillGoods){
                    //无货
                    //状态位 群发
                    redisTemplate.convertAndSend("seckillpush",
                            userRecode.getSkuId() +":0");
                    channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
                    return;//代码不要往下运行了
                }else{
                    //有货
                    OrderRecode orderRecode = new OrderRecode();
                    orderRecode.setUserId(userRecode.getUserId());
                    SeckillGoods sg = (SeckillGoods) redisTemplate.opsForHash().
                            get(RedisConst.SECKILL_GOODS, userRecode.getSkuId().toString());
                    orderRecode.setSeckillGoods(sg);

                    //4、保存抢购资格
                    redisTemplate.opsForValue().set(RedisConst.SECKILL_ORDERS
                             + userRecode.getUserId() + ":" + userRecode.getSkuId(),orderRecode);
                    //手动
                    channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
                }
            }else{
                channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
                return;//代码不要往下运行了
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
